package cn.edu.xmu.oomall.customer.dao;

import cn.edu.xmu.oomall.core.util.JacksonUtil;
import cn.edu.xmu.oomall.core.util.ReturnNo;
import cn.edu.xmu.oomall.core.util.ReturnObject;
import cn.edu.xmu.oomall.customer.mapper.CustomerPoMapper;
import cn.edu.xmu.oomall.customer.model.bo.Address;
import cn.edu.xmu.oomall.customer.model.bo.Customer;
import cn.edu.xmu.oomall.customer.model.po.CustomerPo;
import cn.edu.xmu.oomall.customer.model.po.CustomerPoExample;
import cn.edu.xmu.oomall.customer.model.vo.AddressVo;
import cn.edu.xmu.oomall.customer.model.vo.CaptchaRetVo;
import cn.edu.xmu.oomall.customer.model.vo.ModifyPwdVo;
import cn.edu.xmu.oomall.customer.model.vo.ResetPwdVo;
import cn.edu.xmu.privilegegateway.annotation.util.Common;
import cn.edu.xmu.privilegegateway.annotation.util.RandomCaptcha;
import cn.edu.xmu.privilegegateway.annotation.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Repository;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * @author Jiazhe Yuan
 * @date 2021-12-14 12:15:37
 */
@Repository

public class CustomerAccountDao {
    @Autowired(required = false)
    private CustomerPoMapper customerPoMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private JavaMailSender javaMailSender;

    // 验证码的redis key
    private final static String CAPTCHAKEY = "cp_%s";

    public ReturnObject getUserByName(String username) {
        CustomerPoExample example = new CustomerPoExample();
        CustomerPoExample.Criteria criteria = example.createCriteria();
        criteria.andUserNameEqualTo(username);
        List<CustomerPo> customerPos = null;
        try {
            customerPos = customerPoMapper.selectByExample(example);
        } catch (Exception e) {
            return new ReturnObject<>(ReturnNo.INTERNAL_SERVER_ERR);
        }

        if (null == customerPos || customerPos.isEmpty()) {
            return new ReturnObject(ReturnNo.CUSTOMER_INVALID_ACCOUNT);
        } else {
            CustomerPo customerPo = customerPos.get(0);
            if (customerPo.getState() != Customer.State.NORMAL.getCode().byteValue()) {
                return new ReturnObject(ReturnNo.CUSTOMER_FORBIDDEN);
            }
            Customer customer = Common.cloneVo(customerPo, Customer.class);
            return new ReturnObject(customer);
        }
    }

    public ReturnObject getOwnAccount(Long userId) {
        CustomerPoExample example = new CustomerPoExample();
        CustomerPoExample.Criteria criteria = example.createCriteria();
        List<CustomerPo> customerPos = new ArrayList<>();
        try {
            criteria.andIdEqualTo(userId);
            customerPos = customerPoMapper.selectByExample(example);
        } catch (DataAccessException e) {
            return new ReturnObject<>(ReturnNo.INTERNAL_SERVER_ERR);
        }
        return new ReturnObject<>(customerPos.get(0));
    }

    public ReturnObject modifyPassword(ModifyPwdVo modifyPwdVo) {
        String key = String.format(CAPTCHAKEY, modifyPwdVo.getCaptcha());
        if (!redisUtil.hasKey(key)) {
            return new ReturnObject(ReturnNo.CUSTOMERID_NOTEXIST);
        }
        ReturnObject ret = null;
        try {
            Long id = Long.parseLong(redisUtil.get(key).toString());
            ret = getCustomerPoById(id);

            if (ret.getCode() != ReturnNo.OK) {
                return ret;
            }
        } catch (Exception e) {
            return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR);
        }

        CustomerPo customerPo = (CustomerPo) ret.getData();
        String oldPassword = customerPo.getPassword();
        if (oldPassword.equals(modifyPwdVo.getNewPassword())) {
            return new ReturnObject(ReturnNo.CUSTOMER_PASSWORDSAME);
        }
        redisUtil.del(String.format("customer_%s_%s", customerPo.getUserName(), oldPassword));
        customerPo.setPassword(modifyPwdVo.getNewPassword());

        try {
            customerPoMapper.updateByPrimaryKeySelective(customerPo);
        } catch (Exception e) {
            return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR);
        }
        return new ReturnObject(ReturnNo.OK);
    }

    public ReturnObject modifyOwnAccount(Customer customer) {
        CustomerPo customerPo = Common.cloneVo(customer, CustomerPo.class);
        try {
            customerPoMapper.updateByPrimaryKeySelective(customerPo);
        } catch (Exception e) {
            return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR);
        }
        return new ReturnObject(ReturnNo.OK);
    }

    public ReturnObject resetPassword(ResetPwdVo resetPwdVo) {
        CustomerPoExample customerPoExample = new CustomerPoExample();
        List<CustomerPo> customerPos = null;

        String mobilePattern = "1\\d{10}";
        String emailPattern = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
        String inputInfo = resetPwdVo.getName();
        try {
            if (inputInfo.matches(mobilePattern)) {
                CustomerPoExample.Criteria criteriaMobile = customerPoExample.createCriteria();
                criteriaMobile.andMobileEqualTo(inputInfo);
                customerPos = customerPoMapper.selectByExample(customerPoExample);
                if (customerPos.isEmpty()) {
                    return new ReturnObject(ReturnNo.CUSTOMERID_NOTEXIST, "电话不存在");
                }
            }
            if (inputInfo.matches(emailPattern)) {
                CustomerPoExample.Criteria criteriaEmail = customerPoExample.createCriteria();
                criteriaEmail.andEmailEqualTo(inputInfo);
                customerPos = customerPoMapper.selectByExample(customerPoExample);
                if (customerPos.isEmpty()) {
                    return new ReturnObject(ReturnNo.CUSTOMERID_NOTEXIST, "邮箱不存在");
                }
            }
            CustomerPoExample.Criteria criteriaUsername = customerPoExample.createCriteria();
            criteriaUsername.andUserNameEqualTo(inputInfo);
            customerPos = customerPoMapper.selectByExample(customerPoExample);
            if (customerPos.isEmpty()) {
                return new ReturnObject<>(ReturnNo.CUSTOMERID_NOTEXIST, "用户名不存在");
            }
        } catch (Exception e) {
            return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR);
        }

        String captcha = RandomCaptcha.getRandomString(6);
        while (redisUtil.hasKey(captcha)) {
            captcha = RandomCaptcha.getRandomString(6);
        }

        String id = customerPos.get(0).getId().toString();
        String key = String.format(CAPTCHAKEY, captcha);
        redisUtil.set(key, id, 5 * 6L);

        try {
            SimpleMailMessage msg = new SimpleMailMessage();
            msg.setSubject("[OOMALL]密码重置通知");
            msg.setSentDate(new Date());
            msg.setText("您的验证码是：" + captcha + "\n如果并非本人操作，请忽略此消息，并尽快重置密码以确保账号安全");
            msg.setFrom("529106896@qq.com");
            msg.setTo(customerPos.get(0).getEmail());
            javaMailSender.send(msg);
        } catch (Exception e) {
            //return new ReturnObject(ReturnNo.FIELD_NOTVALID);
        }
        CaptchaRetVo captchaRetVo = new CaptchaRetVo();
        try {
            captchaRetVo.setCaptcha(captcha);
        } catch (Exception e) {
            return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR);
        }
        return new ReturnObject(captchaRetVo);
    }

    public ReturnObject changeCustomerStatus(Long id, Long modifierId, String modifierName, Customer.State state) {
        ReturnObject ret = getCustomerPoById(id);
        if (ret.getCode() != ReturnNo.OK) {
            return new ReturnObject(ReturnNo.RESOURCE_ID_NOTEXIST);
        }

        CustomerPo customerPo = (CustomerPo) getCustomerPoById(id).getData();
        redisUtil.del(String.format("customer_%s_%s", customerPo.getUserName(), customerPo.getPassword()));
        customerPo.setState(state.getCode().byteValue());
        Common.setPoModifiedFields(customerPo, modifierId, modifierName);

        try {
            customerPoMapper.updateByPrimaryKeySelective(customerPo);
            return new ReturnObject(ReturnNo.OK);
        } catch (Exception e) {
            return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR);
        }
    }

    public ReturnObject getCustomerPoById(Long id) {
        try {
            CustomerPo customerPo = customerPoMapper.selectByPrimaryKey(id);
            if (null == customerPo) {
                return new ReturnObject(ReturnNo.RESOURCE_ID_NOTEXIST);
            }
            return new ReturnObject(customerPo);
        } catch (Exception e) {
            return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR);
        }
    }

}
